/*_____________________________________________________________________________
||
|| STM32 Timer Baremetal Driver
||
|| Jinfeng Zhuang, 2024.W18
||
|| Additional Feature: SWIP wrapper
||_____________________________________________________________________________
*/

#include <stdint.h>

/*_____________________________________________________________________________
||
|| Port Related
||
|| Fix compiler issue
||
*/

#ifndef SWIP_SOC_TIMER1
#define SWIP_SOC_TIMER1 (0)
#endif

#ifndef TIMER1_BASE
#define TIMER1_BASE (0)
#endif

#ifndef TIMER2_BASE
#define TIMER2_BASE (0)
#endif

enum
{
    TIMER_CMD_ENABLE = 0,
    TIMER_CMD_PWM,
};

/*_____________________________________________________________________________
||
|| Registers
||
*/

typedef volatile __IO
typedef unsigned int U32;
typedef unsigned char U8;

typedef struct
{
  __IO uint16_t CR1;
  uint16_t  RESERVED0;
  __IO uint16_t CR2;
  uint16_t  RESERVED1;
  __IO uint16_t SMCR;
  uint16_t  RESERVED2;
  __IO uint16_t DIER;
  uint16_t  RESERVED3;
  __IO uint16_t SR;
  uint16_t  RESERVED4;
  __IO uint16_t EGR;
  uint16_t  RESERVED5;
  __IO uint16_t CCMR1;
  uint16_t  RESERVED6;
  __IO uint16_t CCMR2;
  uint16_t  RESERVED7;
  __IO uint16_t CCER;
  uint16_t  RESERVED8;
  __IO uint16_t CNT;
  uint16_t  RESERVED9;
  __IO uint16_t PSC;
  uint16_t  RESERVED10;
  __IO uint16_t ARR;
  uint16_t  RESERVED11;
  __IO uint16_t RCR;
  uint16_t  RESERVED12;
  __IO uint16_t CCR1;
  uint16_t  RESERVED13;
  __IO uint16_t CCR2;
  uint16_t  RESERVED14;
  __IO uint16_t CCR3;
  uint16_t  RESERVED15;
  __IO uint16_t CCR4;
  uint16_t  RESERVED16;
  __IO uint16_t BDTR;
  uint16_t  RESERVED17;
  __IO uint16_t DCR;
  uint16_t  RESERVED18;
  __IO uint16_t DMAR;
  uint16_t  RESERVED19;
} TIM_TypeDef;

static void timer_enable(U32 base, U32 enable)
{
    TIM_TypeDef *tim = (TIM_TypeDef *)base;
    
    TIMx->CCER |= 0x80; // Auto-Preload Enable
    
    if (enable)
    {
        TIMx->CR1 |= 0x1;
    }
    else
    {
        TIMx->CR1 &= ~0x1;
    }
}

/*
 * NOTE: CCMR Writable ONLY if channel is OFF
 * Keep it simple
 */
static void timer_pwm_enable(U32 base, U32 channel)
{
    TIM_TypeDef *tim = (TIM_TypeDef *)base;
    
    switch (channel)
    {
    case 0:
        TIMx->CCMR1 |= (0x60 | 0x08); // mode = PWM1 = 0x60; preload = enable = 0x08
        break;
    case 1:
        TIMx->CCMR1 |= (0x60 | 0x08) << 8; // mode = PWM1 = 0x60; preload = enable = 0x08
        break;
    case 2:
        TIMx->CCMR2 |= (0x60 | 0x08); // mode = PWM1 = 0x60; preload = enable = 0x08
        break;
    case 3:
        TIMx->CCMR2 |= (0x60 | 0x08) << 8; // mode = PWM1 = 0x60; preload = enable = 0x08
        break;
    }

    TIMx->CCER |= 1 << (channel * 4);
}

// freq: us
// Default is count up
// PSC is 16bit, MAX = 65535, 1MHz / 65535 = 15 Hz, which is minimum freq
// Freq between [15Hz, 1MHz]
static void timer_freq_set(U32 base, U32 clock, U32 us)
{
    TIM_TypeDef *TIMx = (TIM_TypeDef *)base;
    
    // First divide to 1MHz
    TIMx->PSC = clock - 1;
    
    // Second, set the auto reload value
    TIMx->ARR = us - 1;
}

static void timer_set_pwm(U32 base, U32 value)
{
    TIM_TypeDef *tim = (TIM_TypeDef *)base;
    
    tim->CCR1 = value;
}

/*_____________________________________________________________________________
||
|| Wrapper of SWIP
||
*/

U32 event_handler_soc_timer(U32 ip, U32 cmd, U32 param1, U32 param2)
{
    U32 base = 0;

	switch (ip)
    {
    case SWIP_SOC_TIMER1:
        base = TIMER1_BASE;
        break;
    }
    
    switch (cmd)
    {
    case TIMER_CMD_ENABLE:
        break;
    case TIMER_CMD_PWM:
        break;
    }
	
	return 0;
}